package com.study.kt._01grammar._02oop

/*
* 对象表达式为了解决java匿名内部类的一些缺陷而产生的
* 1.匿名内部类一定是继承了某个父类或者实现了某个接口
* 2.java运行时会将该匿名内部类当做它实现的接口或者所继承的父类看待，在匿名内部类中定义的其他方法，会被忽略不能使用
* */
// object[:若干父类型，中间用逗号隔开]

/*
*  对象声明(object MyObject) 与 对象表达式的区别
*   1.对象表达式立刻初始化或者执行，对象声明延迟初始化，首次访问时初始化
*   2.伴生对象是在其所对象的类被加载时初始化的，相对于Java的静态初始化
*
* */
fun main() {
    // 1.对象表达式基本用法
    // basicUse()

    // 2.java匿名内部类访问外部类变量，该变量必须有final修饰而kotlin不需要
    // basicUse2()
}


fun basicUse2() {
    var i = 10
    var obj = object {
        fun add() {
            println(++i)
        }
    }
    obj.add()
}

class MyTest {
    /*
    *  匿名对象只能在局部变量范围内或被private修饰的成员变量范围内才能被编译器识别为真正类型
    * 1.此处如果不使用private修饰则test方法无法调用obj的方法
    * 2.basicUser中的obj1为局部变量返回所以才可以使用
    *
    * 如果匿名对象是一个public方法的返回值或者是public类型，那么该方法返回值或者属性的真正类型
    * 就是匿名对象所声明的父类，如果没有声明任何父类则类型为Any，在这种情况下无法使用匿名对象声明的
    * 任何成员，因为Any不包含其所声明的成员
    * */
    private val obj = object {
        fun output() {
            println("output")
        }
    }

    private fun m1() = object {
        val str = "m1"
    }

    internal fun m2() = object {
        val str = "m2"
    }

    fun test() {
        // 获取对象java类型
        println(obj.javaClass)
        println(obj::class.java)
        obj.output()

        //m1是private的方法，可以访问其返回的匿名对象
        m1().str
        //m2不是private，不能返回其返回匿名对象
        // 编译报错
        //m2().str
    }
}

private fun basicUse() {
    // 基本对象表达式
    // java匿名内部类必须继承/实现某个抽象类/接口，kotlin中不必要
    val obj1 = object {
        init {
            println("创建对象表达式")
        }

        val objName = "simple obj"

        fun method() {
            println("I am method")
        }
    }
    println(obj1.objName)

    // 实现某个接口的对象表达式
    val iObj = object : MyInterface {
        override fun myPrint() {
            println("我是接口实现")
        }
    }
    iObj.myPrint()

    // 继承/实现多个父类
    val multyObj = object : MyInterface, MyAbsClz() {
        override fun myPrint() {
            println("multyObj myPrint")
        }

        override fun absPrint() {
            println("absPrint")
        }

        override val age: Int
            get() = 12_000
    }
}

interface MyInterface {
    fun myPrint()
}

abstract class MyAbsClz {
    abstract fun absPrint()
    abstract val age: Int
}